#include <algorithm>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>

// 跨平台支持
#ifdef _WIN32
    #include <direct.h>
    #include <io.h>
    #include <windows.h>
#else
    #include <dirent.h>
    #include <fcntl.h>
    #include <sys/sendfile.h>
    #include <sys/stat.h>
    #include <unistd.h>
#endif

#include "filesystem/os_filesystem.h"
#include "log/logger.h"

// MD5实现相关常量和结构体定义
#define MD5_DIGEST_LENGTH 16

struct MD5_CTX {
    uint32_t state[4];
    uint32_t count[2];
    unsigned char buffer[64];
};

// MD5实现函数声明
static void MD5_Init(MD5_CTX* ctx);
static void MD5_Update(MD5_CTX* ctx, const void* data, size_t len);
static void MD5_Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX* ctx);
static void MD5_Transform(uint32_t state[4], const unsigned char block[64]);

bool os_filesystem::file_exists(const std::string& path)
{
    struct stat buffer;
    return (stat(path.c_str(), &buffer) == 0);
}

bool os_filesystem::create_directory(const std::string& path)
{
    size_t pos = 0;
    do {
        pos = path.find('/', pos + 1);
        std::string dir = path.substr(0, pos);
#ifdef _WIN32
        if (_mkdir(dir.c_str()) != 0 && errno != EEXIST) {
#else
        if (mkdir(dir.c_str(), 0755) != 0 && errno != EEXIST) {
#endif
            return false;
        }
    } while (pos != std::string::npos);
    return true;
}

bool os_filesystem::remove_file(const std::string& path)
{
#ifdef _WIN32
    return _unlink(path.c_str()) == 0;
#else
    return unlink(path.c_str()) == 0;
#endif
}

bool os_filesystem::copy_file(const std::string& source, const std::string& dest)
{
#ifdef _WIN32
    return CopyFileA(source.c_str(), dest.c_str(), FALSE) != 0;
#else
    int src_fd = open(source.c_str(), O_RDONLY);
    if (src_fd < 0) {
        return false;
    }
    // 获取源文件信息
    struct stat src_stat;
    if (fstat(src_fd, &src_stat) < 0) {
        close(src_fd);
        return false;
    }
    int dst_fd = open(dest.c_str(), O_WRONLY | O_CREAT | O_TRUNC, src_stat.st_mode);
    if (dst_fd < 0) {
        close(src_fd);
        return false;
    }
    off_t offset = 0;
    ssize_t sent = 0;
    sent = sendfile(dst_fd, src_fd, &offset, src_stat.st_size);
    if (dst_fd >= 0) {
        if (fdatasync(dst_fd) != 0) {
            LOGW("writeFile: fdatasync failed: %d . Retrying...", errno);
            // 短暂等待后重试
            struct timespec sleep_time = { 0, 5000000 };  // 5毫秒
            nanosleep(&sleep_time, NULL);
            if (fdatasync(dst_fd) != 0) {
                // 再次同步数据都失败了，那只能依赖sync()
                // 函数了和系统调用了，根据多年的经验，两次同步都失败了，就不要在乎这点系统性能损耗，全部同步，否则仍有数据丢失的可能性。
                LOGW("writeFile: sync failed. Trying system(sync).");
                sync();
                system("sync &");
            }
        }
    }
    close(src_fd);
    close(dst_fd);
    return (sent == src_stat.st_size);
#endif
}

os_vector<std::string> os_filesystem::list_files(const std::string& directory)
{
    os_vector_init(std::string, files);
#ifdef _WIN32
    WIN32_FIND_DATAA findData;
    HANDLE hFind = FindFirstFileA((directory + "/*").c_str(), &findData);
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
                files.push_back(directory + "/" + findData.cFileName);
            }
        } while (FindNextFileA(hFind, &findData));
        FindClose(hFind);
    }
#else
    DIR* dir = opendir(directory.c_str());

    if (dir != nullptr) {
        struct dirent* entry;
        while ((entry = readdir(dir)) != nullptr) {
            if (entry->d_type == DT_REG) {  // 普通文件
                files.push_back(directory + "/" + entry->d_name);
            }
        }
        closedir(dir);
    }
#endif
    return files;
}

std::string os_filesystem::calculate_file_md5(const std::string& file_path)
{
    std::ifstream file(file_path, std::ios::binary);
    if (!file) {
        return "";
    }
    MD5_CTX md5Context;
    MD5_Init(&md5Context);
    char buffer[1024];
    while (file.read(buffer, sizeof(buffer)) || file.gcount() > 0) {
        MD5_Update(&md5Context, buffer, file.gcount());
    }
    unsigned char digest[MD5_DIGEST_LENGTH];
    MD5_Final(digest, &md5Context);
    std::stringstream ss;
    for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
        ss << std::hex << std::setw(2) << std::setfill('0') << (int)digest[i];
    }
    return ss.str();
}

std::string os_filesystem::read_file(const std::string& file_path)
{
    std::ifstream file(file_path);
    if (!file.is_open()) {
        return "";
    }
    std::stringstream buffer;
    buffer << file.rdbuf();
    file.close();
    return buffer.str();
}
bool os_filesystem::write_file(const std::string& file_path, const std::string& content)
{
    ssize_t bytes_written = 0;
    const char* data = content.c_str();
    size_t data_size = content.size();
    // 以写模式打开文件，如果不存在则创建，权限为0644
    int fd = open(file_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd < 0) {
        LOGE("writeFile: Failed to open file:%d ", errno);
        return false;
    }
    // 写入数据
    while (bytes_written < static_cast<ssize_t>(data_size)) {
        ssize_t result = write(fd, data + bytes_written, data_size - bytes_written);
        if (result < 0) {
            if (errno == EINTR) {  // 被信号中断，重试
                continue;
            }
            LOGE("writeFile: Failed to write data error: %d", errno);
            close(fd);
            return false;
        }
        bytes_written += result;
    }
    // 同步数据到磁盘
    if (fdatasync(fd) != 0) {
        LOGW("writeFile: fdatasync failed: %d . Retrying...", errno);

        // 短暂等待后重试
        struct timespec sleep_time = { 0, 5000000 };  // 5毫秒
        nanosleep(&sleep_time, NULL);

        if (fdatasync(fd) != 0) {
            LOGW("writeFile: fdatasync failed again error: %d . Using sync().", errno);
            // 再次同步数据都失败了，那只能依赖sync()
            // 函数了和系统调用了，根据多年的经验，两次同步都失败了，就不要在乎这点系统性能损耗，全部同步，否则仍有数据丢失的可能性。
            // 已经到这种层度的错误，已无法关系返回值，只能认为同步成功，已经是最后保命手段
            sync();
            system("sync &");
        }
    }
    if (close(fd) != 0) {
        LOGE("writeFile: Failed to close file: %d", errno);
        return false;
    }

    return true;
}
std::string os_filesystem::calculate_string_md5(const std::string& content)
{
    // 实现计算字符串MD5的逻辑
    unsigned char digest[16];
    MD5_CTX ctx;
    MD5_Init(&ctx);
    MD5_Update(&ctx, content.c_str(), content.length());
    MD5_Final(digest, &ctx);
    std::stringstream ss;
    for (int i = 0; i < 16; i++) {
        ss << std::hex << std::setw(2) << std::setfill('0') << (int)digest[i];
    }
    return ss.str();
}

bool os_filesystem::directory_exists(const std::string& path)
{
    struct stat info;
    if (stat(path.c_str(), &info) != 0) {
        return false;
    }
    return S_ISDIR(info.st_mode);
}

os_vector<std::string> os_filesystem::list_subdirectories(const std::string& path)
{
    os_vector_init(std::string, subdirectories);
    DIR* dir = opendir(path.c_str());
    if (dir) {
        struct dirent* entry;
        while ((entry = readdir(dir)) != nullptr) {
            if (entry->d_type == DT_DIR && strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
                subdirectories.push_back(entry->d_name);
            }
        }
        closedir(dir);
    }
    return subdirectories;
}

bool os_filesystem::remove_directory(const std::string& path)
{
#ifdef _WIN32
    return _rmdir(path.c_str()) == 0;
#else
    struct dirent* entry;
    bool success = true;
    DIR* dir = opendir(path.c_str());
    if (!dir) {
        LOGE("Failed to open directory: %s  error:%d", path.c_str(), errno);
        return false;
    }
    while ((entry = readdir(dir)) != nullptr && success) {
        // 跳过当前目录和父目录
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }
        std::string full_path = path + "/" + entry->d_name;
        if (entry->d_type == DT_DIR) {
            // 递归删除子目录
            success = remove_directory(full_path);
        } else {
            // 删除文件
            if (unlink(full_path.c_str()) != 0) {
                LOGE("Failed to remove file: %s, error: %d", full_path.c_str(), errno);
                success = false;
            }
        }
    }
    closedir(dir);
    // 删除当前空目录
    if (success && rmdir(path.c_str()) != 0) {
        LOGE("Failed to remove directory: %s error: %d", path.c_str(), errno);
        success = false;
    }

    return success;
#endif
}

// MD5算法实现
static const uint32_t K[] = { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613,
                              0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193,
                              0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d,
                              0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
                              0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122,
                              0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
                              0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244,
                              0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
                              0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb,
                              0xeb86d391 };

static const uint32_t S[] = { 7,  12, 17, 22, 7,  12, 17, 22, 7,  12, 17, 22, 7,  12, 17, 22, 5,  9,  14, 20, 5,  9,
                              14, 20, 5,  9,  14, 20, 5,  9,  14, 20, 4,  11, 16, 23, 4,  11, 16, 23, 4,  11, 16, 23,
                              4,  11, 16, 23, 6,  10, 15, 21, 6,  10, 15, 21, 6,  10, 15, 21, 6,  10, 15, 21 };

static uint32_t F(uint32_t x, uint32_t y, uint32_t z)
{
    return (x & y) | (~x & z);
}
static uint32_t G(uint32_t x, uint32_t y, uint32_t z)
{
    return (x & z) | (y & ~z);
}
static uint32_t H(uint32_t x, uint32_t y, uint32_t z)
{
    return x ^ y ^ z;
}
static uint32_t I(uint32_t x, uint32_t y, uint32_t z)
{
    return y ^ (x | ~z);
}

static uint32_t rol(uint32_t value, uint32_t shift)
{
    return (value << shift) | (value >> (32 - shift));
}

static void MD5_Init(MD5_CTX* ctx)
{
    ctx->state[0] = 0x67452301;
    ctx->state[1] = 0xefcdab89;
    ctx->state[2] = 0x98badcfe;
    ctx->state[3] = 0x10325476;
    ctx->count[0] = 0;
    ctx->count[1] = 0;
}

static void MD5_Update(MD5_CTX* ctx, const void* data, size_t len)
{
    const unsigned char* input = (const unsigned char*)data;
    size_t index = (ctx->count[0] >> 3) & 0x3f;
    if ((ctx->count[0] += (len << 3)) < (len << 3)) {
        ctx->count[1]++;
    }
    ctx->count[1] += (len >> 29);

    size_t i = 0, partLen = 64 - index;
    if (len >= partLen) {
        memcpy(&ctx->buffer[index], input, partLen);
        MD5_Transform(ctx->state, ctx->buffer);

        for (i = partLen; i + 63 < len; i += 64) {
            MD5_Transform(ctx->state, &input[i]);
        }
        index = 0;
    } else {
        i = 0;
    }

    memcpy(&ctx->buffer[index], &input[i], len - i);
}

static void MD5_Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX* ctx)
{
    unsigned char bits[8];
    size_t index, padLen;

    for (size_t i = 0; i < 8; i++) {
        bits[i] = (ctx->count[i >> 2] >> ((i & 3) << 3)) & 0xff;
    }

    index = (ctx->count[0] >> 3) & 0x3f;
    padLen = (index < 56) ? (56 - index) : (120 - index);
    static const unsigned char padding[64] = { 0x80 };
    MD5_Update(ctx, padding, padLen);
    MD5_Update(ctx, bits, 8);

    for (size_t i = 0; i < MD5_DIGEST_LENGTH; i++) {
        digest[i] = (ctx->state[i >> 2] >> ((i & 3) << 3)) & 0xff;
    }
}

static void MD5_Transform(uint32_t state[4], const unsigned char block[64])
{
    uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];

    for (size_t i = 0; i < 16; i++) {
        x[i] = (uint32_t)(block[i * 4]) | ((uint32_t)(block[i * 4 + 1]) << 8) | ((uint32_t)(block[i * 4 + 2]) << 16) |
               ((uint32_t)(block[i * 4 + 3]) << 24);
    }

    for (size_t i = 0; i < 64; i++) {
        uint32_t f, g;
        if (i < 16) {
            f = F(b, c, d);
            g = i;
        } else if (i < 32) {
            f = G(b, c, d);
            g = (5 * i + 1) % 16;
        } else if (i < 48) {
            f = H(b, c, d);
            g = (3 * i + 5) % 16;
        } else {
            f = I(b, c, d);
            g = (7 * i) % 16;
        }
        f += a + K[i] + x[g];
        a = d;
        d = c;
        c = b;
        b += rol(f, S[i]);
    }

    state[0] += a;
    state[1] += b;
    state[2] += c;
    state[3] += d;
}